using System.Text;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(Rigidbody2D), typeof(Animator), typeof(PhysicsCheck))]
public class Enemy : MonoBehaviour {

    [Header("基本参数")]
    public float normalSpeed;
    public float chaseSpeed;
    [HideInInspector] public float currentSpeed;
    public Vector3 faceDir;
    public float hurtForce;
    public Vector3 spwanPoint;  // 出生点

    [HideInInspector] public Transform attacker;

    [HideInInspector] public Rigidbody2D rb;
    [HideInInspector] public PhysicsCheck physicsCheck;
    [HideInInspector] public Animator ani;

    [Header("检测")]
    public Vector2 centerOffset;    // 检测中心点偏移
    public Vector2 checkSize;       // 检测盒大小
    public float checkDistance;     // 检测距离
    public LayerMask attackLayer;   // 检测、攻击的Layer

    [Header("计时器")]
    public float waitTime;
    public float waitCounter;
    public bool isWait;
    public float lostTime;
    public float lostTimeCounter;

    [Header("状态")]
    public bool isHurt;
    public bool isDead;

    #region 状态机
    private BaseState currentState;     // 当前
    protected BaseState patrolState;    // 巡逻
    protected BaseState chaseState;     // 追击
    protected BaseState skillState;     // 技能
    #endregion 状态机

    protected virtual void Awake() {
        rb = GetComponent<Rigidbody2D>();
        ani = GetComponent<Animator>();
        physicsCheck = GetComponent<PhysicsCheck>();

        currentSpeed = normalSpeed;
        waitCounter = waitTime;
        isWait = false;
        spwanPoint = transform.position;    // 出生点初始化
    }

    private void OnEnable() {
        currentState = patrolState;     // 初始状态为巡逻状态
        currentState.OnEnter(this);         // 执行巡逻状态进入时的逻辑
    }

    private void Update() {
        faceDir = new Vector3(-transform.localScale.x, 0, 0);  // 本项目敌人素材初始面向都是朝左，所以localScale.x和velocity.x是相反的

        currentState.LogicUpdate();     // 执行当前状态的逻辑判断
        TimeCounter();
    }

    private void OnDisable() {
        currentState.OnExit();
    }

    private void FixedUpdate() {
        if (!isHurt && !isDead && !isWait) {
            Move();
        }
        
        currentState.PhysicsUpdate();   // 执行当前状态的物理判断，物体的物理状态相关的更新要放在FixedUpdate中执行
    }

    public virtual void Move() {  // virtual虚函数，子类可以重写
        // 针对于蜗牛，当且仅当蜗牛播放伸出去的动画时才进行位移
        if (!ani.GetCurrentAnimatorStateInfo(0).IsName("SnailPreMove") && !ani.GetCurrentAnimatorStateInfo(0).IsName("SnailRecover")) {
            rb.velocity = new Vector2(currentSpeed * faceDir.x * Time.deltaTime, rb.velocity.y);
        }
    }

    public virtual Vector3 GetNewPoint() {
        return transform.position;
    }

    #region 事件执行方法
    #region UnityEvent
    public void OnTakeDamage(Transform attackTrans) {
        // 转身
        attacker = attackTrans;
        if (attackTrans.position.x - transform.position.x > 0) {
            transform.localScale = new Vector3(-1, 1, 1);
        }
        if (attackTrans.position.x - transform.position.x < 0) {
            transform.localScale = new Vector3(1, 1, 1);
        }

        // 受伤被击退
        isHurt = true;
        rb.velocity = new Vector2(0, rb.velocity.y);
        ani.SetTrigger("hurt");
        Vector2 dir = new Vector2(transform.position.x - attackTrans.position.x, 0).normalized;

        StartCoroutine(OnHurt(dir));
    }

    public void OnDie() {
        gameObject.layer = LayerMask.NameToLayer("Ignore Raycast");  // 死亡后将其layer改为Ignore Raycast
        ani.SetBool("isDead", true);
        isDead = true;
    }
    #endregion UnityEvent

    /*
        受伤逻辑的协程
    */
    private IEnumerator OnHurt(Vector2 dir) {
        // 被击退
        rb.AddForce(dir * hurtForce, ForceMode2D.Impulse);
        yield return new WaitForSeconds(0.45f);
        // 受伤状态结束
        isHurt = false;
    }

    /*
        在死亡动画播放完毕后，把敌人对象销毁
    */
    public void DestoryAfterAnimation () {
        Destroy(this.gameObject);
    }
    #endregion 事件执行方法

    public virtual void OnDrawGizmosSelected() {
        Gizmos.DrawWireSphere(transform.position + (Vector3)centerOffset + new Vector3(checkDistance * (-transform.localScale.x), 0, 0), 0.2f);    
    }

    public virtual bool FoundPlayer() {
        return Physics2D.BoxCast(transform.position + (Vector3)centerOffset, checkSize, 0, faceDir, checkDistance, attackLayer);
    }

    public void SwitchState(NPCState state) {
        // 这段代码使用了C# 8.0中的switch表达式语法。它通过匹配枚举类型state的不同取值来选择对应的处理逻辑。
        // 这种用法可以简化多个if-else语句的代码，提高可读性和简洁性。
        var newState = state switch {
            NPCState.Patrol => patrolState, // 当state的值为NPCState.Patrol时，将patrolState赋值给newState。
            NPCState.Chase => chaseState,   // 当state的值为NPCState.Chase时，将chaseState赋值给newState。
            NPCState.Skill => skillState,   // 当state的值位NPCState.Skill时，将skillState赋值给newState。
            _ => null                       // 对于其他任何枚举值，使用_表示默认情况，将null赋值给newState。
        };

        currentState.OnExit();
        currentState = newState;
        currentState.OnEnter(this);
    }

    /*
        计时器
    */
    private void TimeCounter() {
        // 撞墙后等待
        if (isWait) {
            waitCounter -= Time.deltaTime;
            // 等待完毕后转身
            if (waitCounter <= 0) {
                transform.localScale = new Vector3(faceDir.x, 1, 1);
                ani.SetBool("isWalk", true);
                isWait = false;
                waitCounter = waitTime;
            }
        }

        // 追击、丢失目标
        if (!FoundPlayer()) {
            if (lostTimeCounter > 0)
                lostTimeCounter -= Time.deltaTime;
            else
                lostTimeCounter = 0;
        } else {
            lostTimeCounter = lostTime;
        }
    }

}
